﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Configuration;
using System.IO;
using System.ServiceModel.Configuration;
using System.ServiceModel.Web;
using System.Threading;
using BbsbWebService.Classes;
using BbsbWebService.Enums;
using BbsbWebService.Repositories;
using System.Text;
using BbsbWebService.Tasks;
using BbsbWebService.Classes.Plugins.Bbsb;
using BbsbWebService.Classes.Plugins.KeyMap;

namespace BbsbWebService.Service
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    [ServiceKnownType("AllServiceKnownTypes", typeof(AppSettings))]
    public class BbsbService : IBbsbService, IWebPageService
    {
        #region Private Members

        WebServiceHost _host;

        #endregion

        #region IBbsbService Members

        public ControllableItem[] GetAllItems()
        {
            ControllableItem[] retVal = RepositoryInstances.ItemRepository.Items.ToArray();
            return retVal;
        }

        public ControllableItem GetItem(Guid id)
        {
            return RepositoryInstances.ItemRepository.GetItem(id);
        }

        public BaseGroup[] GetGroups(GroupType filter)
        {
            BaseGroup[] items;
            if (filter == GroupType.All)
            {
                items = ToBaseGroupItem(RepositoryInstances.GroupRepository.Items);
            }
            else
            {
                items = ToBaseGroupItem(RepositoryInstances.GroupRepository.Items.Where(o => o.Type == filter));
            }
            return items;
        }

        public Group[] GetDetailedGroups(GroupType filter)
        {
            Group[] items;
            if (filter == GroupType.All)
            {
                items = RepositoryInstances.GroupRepository.Items.ToArray();
            }
            else
            {
                items = RepositoryInstances.GroupRepository.Items.Where(o => o.Type == filter).ToArray();
            }
            return items;
        }

        public Group GetGroup(Guid id)
        {
            return RepositoryInstances.GroupRepository.GetItem(id);
        }

        public PowerState SendPower(Guid id, PowerOption option)
        {
            return RepositoryInstances.SendPower(id, option);
        }

        public PowerState PowerOn(Guid id)
        {
            return SendPower(id, PowerOption.On);
        }

        public PowerState PowerOff(Guid id)
        {
            return SendPower(id, PowerOption.Off);
        }

        public PowerState Toggle(Guid id)
        {
            return RepositoryInstances.ItemRepository.Toggle(id);
        }

        public void UpdateState(Guid id, PowerState state)
        {
            RepositoryInstances.ItemRepository.UpdateState(id, state);
        }

        public void SaveItem(ControllableItem item)
        {
            RepositoryInstances.ItemRepository.SaveItem(item);
        }

        public void SaveGroup(Group group)
        {
            RepositoryInstances.GroupRepository.SaveItem(group);
        }

        public void RemoveItem(ControllableItem item)
        {
            RepositoryInstances.ItemRepository.RemoveItem(item);
        }

        public void RemoveGroup(Group group)
        {
            RepositoryInstances.GroupRepository.RemoveItem(group);
        }

        public BaseTask[] GetTasks()
        {
            BaseTask[] tasks = RepositoryInstances.TaskRepository.Items.ToArray();
            return tasks;
        }

        public void Sleep(Guid id, int delay)
        {
            var item = RepositoryInstances.GetItem(id);

            if (item != null)
            {
                OneOffTask task = new OneOffTask(DateTime.Now.AddMinutes(delay));
                task.Item = item;
                task.PowerOption = PowerOption.Off;
                task.Name = "Sleep function autogenerated";
                task.Disabled = false;
                RepositoryInstances.TaskRepository.SaveItem(task);
            }
        }

        public BaseTask GetTask(Guid id)
        {
            return RepositoryInstances.TaskRepository.GetItem(id);
        }

        public void SaveTask(BaseTask task)
        {
            RepositoryInstances.TaskRepository.SaveItem(task);
        }

        public void RemoveTask(BaseTask task)
        {
            RepositoryInstances.TaskRepository.RemoveItem(task);
        }

        #endregion

        #region IWebPageService Members

        public Stream GetWebFile(string filetype, string filename)
        {
            Stream retVal = null;

            try
            {
                string extension = Path.GetExtension(filename).Replace(".", string.Empty);

                if (!filename.IsNullOrEmpty() &&
                    !filetype.IsNullOrEmpty())
                {
                    if (AppSettings.MimeTypes.ContainsKey(extension))
                    {
                        FileInfo file = new FileInfo(Path.Combine(AppSettings.WebPageBaseDirectory.FullName, string.Format("{0}/{1}", filetype, filename)));
                        if (File.Exists(file.FullName))
                        {
                            FileStream stream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read);
                            retVal = stream;
                        }
                    }

                    WebOperationContext.Current.OutgoingResponse.ContentType = GetContentType(extension);
                }
            }
            catch (Exception ex)
            {
                Logging.Logger.Instance.LogException(ex, "Error getting web file {0},{1}", filetype, filename);
            }
            return retVal;
        }

        #endregion

        public void Initialise(Uri uri)
        {
            _host = new WebServiceHost(this, uri);
            WebHttpBinding binding = new WebHttpBinding
            {
                CrossDomainScriptAccessEnabled = true
            };
            var behaviour = new WebHttpBehavior
            {
                HelpEnabled = true,
                FaultExceptionEnabled = true,
                DefaultOutgoingRequestFormat = WebMessageFormat.Json,
                DefaultOutgoingResponseFormat = WebMessageFormat.Json,
                AutomaticFormatSelectionEnabled = true
            };
            _host.AddServiceEndpoint(typeof(IBbsbService), binding, string.Empty)
                .Behaviors.Add(behaviour);
            _host.AddServiceEndpoint(typeof(IWebPageService), new WebHttpBinding(), "web")
                .Behaviors.Add(new WebHttpBehavior());
            _host.Open();
        }

        private BaseGroup[] ToBaseGroupItem(IEnumerable<Group> bobs)
        {
            List<BaseGroup> items = new List<BaseGroup>();
            foreach (var bob in bobs)
            {
                BaseGroup item = new BaseGroup();
                item.Id = bob.Id;
                item.Name = bob.Name;
                item.Type = bob.Type;
                items.Add(item);
            }
            return items.ToArray();
        }

        public void StopService()
        {
            if (_host != null &&
                _host.State == CommunicationState.Opened)
            {
                _host.Close();
            }
        }

        private string GetContentType(string type)
        {
            string retVal = string.Empty;

            if (AppSettings.MimeTypes.ContainsKey(type))
            {
                retVal = AppSettings.MimeTypes[type];
            }

            return retVal;
        }
    }
}
